mercury-rails 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +152 -0
  3. data/VERSION +1 -0
  4. data/app/assets/images/mercury/button.png +0 -0
  5. data/app/assets/images/mercury/clippy.png +0 -0
  6. data/app/assets/images/mercury/default-snippet.png +0 -0
  7. data/app/assets/images/mercury/loading-dark.gif +0 -0
  8. data/app/assets/images/mercury/loading-light.gif +0 -0
  9. data/app/assets/images/mercury/search-icon.png +0 -0
  10. data/app/assets/images/mercury/toolbar/editable/buttons.png +0 -0
  11. data/app/assets/images/mercury/toolbar/markupable/buttons.png +0 -0
  12. data/app/assets/images/mercury/toolbar/primary/_expander.png +0 -0
  13. data/app/assets/images/mercury/toolbar/primary/_pressed.png +0 -0
  14. data/app/assets/images/mercury/toolbar/primary/historypanel.png +0 -0
  15. data/app/assets/images/mercury/toolbar/primary/insertcharacter.png +0 -0
  16. data/app/assets/images/mercury/toolbar/primary/insertlink.png +0 -0
  17. data/app/assets/images/mercury/toolbar/primary/insertmedia.png +0 -0
  18. data/app/assets/images/mercury/toolbar/primary/inserttable.png +0 -0
  19. data/app/assets/images/mercury/toolbar/primary/inspectorpanel.png +0 -0
  20. data/app/assets/images/mercury/toolbar/primary/notespanel.png +0 -0
  21. data/app/assets/images/mercury/toolbar/primary/objectspanel.png +0 -0
  22. data/app/assets/images/mercury/toolbar/primary/preview.png +0 -0
  23. data/app/assets/images/mercury/toolbar/primary/redo.png +0 -0
  24. data/app/assets/images/mercury/toolbar/primary/save.png +0 -0
  25. data/app/assets/images/mercury/toolbar/primary/todospanel.png +0 -0
  26. data/app/assets/images/mercury/toolbar/primary/undo.png +0 -0
  27. data/app/assets/images/mercury/toolbar/snippetable/buttons.png +0 -0
  28. data/app/assets/javascripts/mercury.js +30 -0
  29. data/app/assets/javascripts/mercury/dialog.js.coffee +75 -0
  30. data/app/assets/javascripts/mercury/dialogs/backcolor.js.coffee +6 -0
  31. data/app/assets/javascripts/mercury/dialogs/forecolor.js.coffee +6 -0
  32. data/app/assets/javascripts/mercury/dialogs/formatblock.js.coffee +4 -0
  33. data/app/assets/javascripts/mercury/dialogs/objectspanel.js.coffee +10 -0
  34. data/app/assets/javascripts/mercury/dialogs/style.js.coffee +4 -0
  35. data/app/assets/javascripts/mercury/history_buffer.js.coffee +30 -0
  36. data/app/assets/javascripts/mercury/mercury.js.coffee +293 -0
  37. data/app/assets/javascripts/mercury/modal.js.coffee +177 -0
  38. data/app/assets/javascripts/mercury/modals/htmleditor.js.coffee +10 -0
  39. data/app/assets/javascripts/mercury/modals/insertcharacter.js.coffee +4 -0
  40. data/app/assets/javascripts/mercury/modals/insertlink.js.coffee +92 -0
  41. data/app/assets/javascripts/mercury/modals/insertmedia.js.coffee +72 -0
  42. data/app/assets/javascripts/mercury/modals/insertsnippet.js.coffee +11 -0
  43. data/app/assets/javascripts/mercury/modals/inserttable.js.coffee +56 -0
  44. data/app/assets/javascripts/mercury/native_extensions.js.coffee +47 -0
  45. data/app/assets/javascripts/mercury/page_editor.js.coffee +139 -0
  46. data/app/assets/javascripts/mercury/palette.js.coffee +29 -0
  47. data/app/assets/javascripts/mercury/panel.js.coffee +97 -0
  48. data/app/assets/javascripts/mercury/region.js.coffee +103 -0
  49. data/app/assets/javascripts/mercury/regions/editable.js.coffee +546 -0
  50. data/app/assets/javascripts/mercury/regions/markupable.js.coffee +380 -0
  51. data/app/assets/javascripts/mercury/regions/snippetable.js.coffee +127 -0
  52. data/app/assets/javascripts/mercury/select.js.coffee +40 -0
  53. data/app/assets/javascripts/mercury/snippet.js.coffee +92 -0
  54. data/app/assets/javascripts/mercury/snippet_toolbar.js.coffee +69 -0
  55. data/app/assets/javascripts/mercury/statusbar.js.coffee +25 -0
  56. data/app/assets/javascripts/mercury/table_editor.js.coffee +266 -0
  57. data/app/assets/javascripts/mercury/toolbar.button.js.coffee +152 -0
  58. data/app/assets/javascripts/mercury/toolbar.button_group.js.coffee +42 -0
  59. data/app/assets/javascripts/mercury/toolbar.expander.js.coffee +56 -0
  60. data/app/assets/javascripts/mercury/toolbar.js.coffee +72 -0
  61. data/app/assets/javascripts/mercury/tooltip.js.coffee +67 -0
  62. data/app/assets/javascripts/mercury/uploader.js.coffee +213 -0
  63. data/app/assets/javascripts/mercury/websocket.js.coffee +34 -0
  64. data/app/assets/stylesheets/mercury.css +31 -0
  65. data/app/assets/stylesheets/mercury/dialog.scss +178 -0
  66. data/app/assets/stylesheets/mercury/mercury.scss +119 -0
  67. data/app/assets/stylesheets/mercury/modal.scss +192 -0
  68. data/app/assets/stylesheets/mercury/statusbar.scss +23 -0
  69. data/app/assets/stylesheets/mercury/toolbar.scss +417 -0
  70. data/app/assets/stylesheets/mercury/tooltip.scss +26 -0
  71. data/app/assets/stylesheets/mercury/uploader.scss +109 -0
  72. data/app/controllers/images_controller.rb +19 -0
  73. data/app/controllers/mercury_controller.rb +20 -0
  74. data/app/models/image.rb +14 -0
  75. data/app/views/layouts/mercury.html.haml +12 -0
  76. data/app/views/mercury/modals/character.html.haml +252 -0
  77. data/app/views/mercury/modals/htmleditor.html.haml +8 -0
  78. data/app/views/mercury/modals/link.html.haml +31 -0
  79. data/app/views/mercury/modals/media.html.haml +33 -0
  80. data/app/views/mercury/modals/sanitizer.html.haml +4 -0
  81. data/app/views/mercury/modals/table.html.haml +49 -0
  82. data/app/views/mercury/palettes/backcolor.html.haml +79 -0
  83. data/app/views/mercury/palettes/forecolor.html.haml +79 -0
  84. data/app/views/mercury/panels/history.html.haml +0 -0
  85. data/app/views/mercury/panels/notes.html.haml +0 -0
  86. data/app/views/mercury/panels/snippets.html.haml +10 -0
  87. data/app/views/mercury/selects/formatblock.html.haml +10 -0
  88. data/app/views/mercury/selects/style.html.haml +4 -0
  89. data/app/views/mercury/snippets/example.html.haml +2 -0
  90. data/app/views/mercury/snippets/example_options.html.haml +16 -0
  91. data/config/engine.rb +6 -0
  92. data/config/routes.rb +15 -0
  93. data/db/migrate/20110526035601_create_images.rb +11 -0
  94. data/features/editing/basic.feature +11 -0
  95. data/features/step_definitions/debug_steps.rb +14 -0
  96. data/features/step_definitions/web_steps.rb +211 -0
  97. data/features/support/env.rb +46 -0
  98. data/features/support/paths.rb +35 -0
  99. data/features/support/selectors.rb +42 -0
  100. data/lib/mercury-rails.rb +4 -0
  101. data/log/.gitkeep +0 -0
  102. data/mercury-rails.gemspec +230 -0
  103. data/spec/javascripts/mercury/dialog_spec.js.coffee +258 -0
  104. data/spec/javascripts/mercury/history_buffer_spec.js.coffee +79 -0
  105. data/spec/javascripts/mercury/mercury_spec.js.coffee +52 -0
  106. data/spec/javascripts/mercury/native_extensions_spec.js.coffee +66 -0
  107. data/spec/javascripts/mercury/page_editor_spec.js.coffee +435 -0
  108. data/spec/javascripts/mercury/palette_spec.js.coffee +51 -0
  109. data/spec/javascripts/mercury/panel_spec.js.coffee +147 -0
  110. data/spec/javascripts/mercury/region_spec.js.coffee +261 -0
  111. data/spec/javascripts/mercury/regions/_editable_.js.coffee +0 -0
  112. data/spec/javascripts/mercury/regions/_markupable_.js.coffee +0 -0
  113. data/spec/javascripts/mercury/regions/snippetable_spec.js.coffee +368 -0
  114. data/spec/javascripts/mercury/select_spec.js.coffee +51 -0
  115. data/spec/javascripts/mercury/snippet_spec.js.coffee +246 -0
  116. data/spec/javascripts/mercury/snippet_toolbar_spec.js.coffee +186 -0
  117. data/spec/javascripts/mercury/statusbar_spec.js.coffee +78 -0
  118. data/spec/javascripts/mercury/table_editor_spec.js.coffee +192 -0
  119. data/spec/javascripts/mercury/toolbar.button_group_spec.js.coffee +92 -0
  120. data/spec/javascripts/mercury/toolbar.button_spec.js.coffee +341 -0
  121. data/spec/javascripts/mercury/toolbar.expander_spec.js.coffee +120 -0
  122. data/spec/javascripts/mercury/toolbar_spec.js.coffee +152 -0
  123. data/spec/javascripts/mercury/tooltip_spec.js.coffee +188 -0
  124. data/spec/javascripts/mercury/uploader_spec.js.coffee +512 -0
  125. data/spec/javascripts/responses/blank.html +1 -0
  126. data/spec/javascripts/spec_helper.js +513 -0
  127. data/spec/javascripts/templates/mercury/dialog.html +2 -0
  128. data/spec/javascripts/templates/mercury/page_editor.html +24 -0
  129. data/spec/javascripts/templates/mercury/palette.html +16 -0
  130. data/spec/javascripts/templates/mercury/panel.html +16 -0
  131. data/spec/javascripts/templates/mercury/region.html +2 -0
  132. data/spec/javascripts/templates/mercury/regions/snippetable.html +4 -0
  133. data/spec/javascripts/templates/mercury/select.html +16 -0
  134. data/spec/javascripts/templates/mercury/snippet.html +1 -0
  135. data/spec/javascripts/templates/mercury/snippet_toolbar.html +16 -0
  136. data/spec/javascripts/templates/mercury/statusbar.html +7 -0
  137. data/spec/javascripts/templates/mercury/table_editor.html +65 -0
  138. data/spec/javascripts/templates/mercury/toolbar.button.html +64 -0
  139. data/spec/javascripts/templates/mercury/toolbar.button_group.html +9 -0
  140. data/spec/javascripts/templates/mercury/toolbar.expander.html +18 -0
  141. data/spec/javascripts/templates/mercury/toolbar.html +10 -0
  142. data/spec/javascripts/templates/mercury/tooltip.html +12 -0
  143. data/spec/javascripts/templates/mercury/uploader.html +11 -0
  144. data/vendor/assets/javascripts/jquery-1.6.js +8865 -0
  145. data/vendor/assets/javascripts/jquery-ui-1.8.13.custom.min.js +249 -0
  146. data/vendor/assets/javascripts/jquery-ui-1.8.13.sortable.custom.js +1078 -0
  147. data/vendor/assets/javascripts/jquery.easing.js +173 -0
  148. data/vendor/assets/javascripts/jquery.json2.js +178 -0
  149. data/vendor/assets/javascripts/jquery.serialize_object.js +16 -0
  150. data/vendor/assets/javascripts/jquery.ujs.js +289 -0
  151. data/vendor/assets/javascripts/liquidmetal.js +88 -0
  152. data/vendor/assets/javascripts/showdown.js +1362 -0
  153. metadata +364 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Jeremy Jackson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,152 @@
1
+ = Mercury Editor
2
+
3
+ Mercury Editor is a fully featured editor much like TinyMCE or CKEditor, but with a different usage paradigm. It
4
+ expects that an entire page is something that can be editable, and allows different types of editable regions to be
5
+ specified. It displays a single toolbar for every region on the page, and uses the HTML5 contentEditable features on
6
+ block elements, instead of iframes, which allows for CSS to be applied in ways that most other editors can't handle.
7
+
8
+ Mercury has been written using CoffeeScript and jQuery for the Javascript portions, and is written on top of Rails 3.1.
9
+
10
+
11
+ == Browser Support
12
+
13
+ Mercury has been written for the future, and thus doesn't support legacy browsers or browsers that don't follow the W3C
14
+ specifications for content editing. Any browser will be supported if they support the W3C specification in the future,
15
+ but there aren't plans for adding support for alternate implementations at this time.
16
+
17
+ Supported Browsers:
18
+ * Chrome 10+
19
+ * Safari 5+
20
+ * Firefox 4+
21
+
22
+
23
+ == The Story
24
+
25
+ I was looking for a fully featured editor that didn't use iframes, and there weren't any decent ones. My primary goal
26
+ was to have areas that were editable, but that also allowed CSS to flow naturally. A few have cropped up since then
27
+ (Aloha Editor for instance), and as good as they are, none had all the features I was looking for.
28
+
29
+ Mercury was written to be as simple as possible, while also providing an advanced feature set. Instead of complex
30
+ configuration, we chose a mix of configuration and code simplicity, which should give you a much better chance at
31
+ customizing Mercury to suit your exact needs. This doesn't mean there's not configuration, and what's there provides
32
+ much of what you'll need, but efforts were taken to keep it simple and powerful.
33
+
34
+ Even though it's a great editor, Mercury Editor may not be the best for your needs (based on browser support, javascript
35
+ library, etc.) so here's a list of some other editors that you might want to check out:
36
+
37
+ * {Aloha Editor}[http://www.aloha-editor.org/]
38
+ * {jHtmlArea}[http://jhtmlarea.codeplex.com/]
39
+ * {MarkItUp}[http://markitup.jaysalvat.com/home/]
40
+ * {TinyMCE}[http://tinymce.moxiecode.com/]
41
+ * {CKEditor}[http://ckeditor.com/]
42
+ * {NicEdit}[http://nicedit.com/]
43
+
44
+
45
+ == Project Details
46
+
47
+ === WYSIWYG Editors Suck
48
+
49
+ They just do. Which as I've learned, is primarily due to the browser implementations. Don't get me wrong, what the
50
+ browsers have implemented is amazing, because it's hard stuff, plain and simple. But if you're expecting a WYSIWYG
51
+ editor to solve all your content problems you're wrong. A better perception is that it will solve many of them, but
52
+ shifts some into a new area.
53
+
54
+ With that being said, Mercury tries to solve many of those issues and succeeds to a great degree, but alas, it's nearly
55
+ impossible to address everything, and the browsers don't expose enough to fix some things. This is true for every
56
+ editor that I've looked into as well.
57
+
58
+ It's important to understand this, and the details are more suited for long nerdy blog posts, so they won't be covered
59
+ here.
60
+
61
+ === The Code and Why
62
+
63
+ ==== CoffeeScript
64
+
65
+ Mercury has been written entirely in CoffeeScript because it simplifies a lot of the patterns that are used, and allows
66
+ for very readable code. The goal was to provide good readable code that could be adjusted based on need, instead of a
67
+ complex configuration that makes the code harder to understand and tweak.
68
+
69
+ ==== jQuery
70
+
71
+ jQuery was used as the javascript library, but is primarily used for the selectors, traversing, and manipulating the
72
+ DOM. Chaining is kept to a minimum for readability, and even though much of Mercury could've been written as jQuery
73
+ plugins, it was not.
74
+
75
+ ==== Rails
76
+
77
+ With the asset handling that comes bundled with Rails 3.1, Rails Engines, and the gem tools, there really wasn't any
78
+ other option. The javascript from Mercury can be used by any back end system, and isn't limited to Rails. Many of the
79
+ features do require a back end, and that stuff would have to be rewritten in whatever language you wanted support for.
80
+ The coffeescript files can be found in the repo, and I would be fully supportive of anyone who wanted to add support for
81
+ different back end frameworks or languages.
82
+
83
+ ==== Specs / Integration Tests
84
+
85
+ Mercury is fully tested using Jasmine (via Evergreen) and Cucumber. You can clone the project to run the full suite.
86
+
87
+ rake spec:javascripts
88
+ rake cucumber
89
+
90
+
91
+ == Features
92
+
93
+ The feature list is actually pretty long, so here's a short list that need highlighting.
94
+
95
+ * Previewing: Preview content while you're working to see exactly how it'll look.
96
+ * Link Tools: Insert and edit links, including TOC/Bookmark links.
97
+ * Media Tools: Insert and edit images, youtube videos, and vimeo videos.
98
+ * Image Uploading: Drag images from your desktop and they'll be automatically uploaded and inserted.
99
+ * Table Editing: Advanced table editing and creation.
100
+ * Snippets: Insert and edit predefined and reusable bits of markup/code using drag and drop.
101
+ * Notes: Attach notes to any page and communicate with other content authors.
102
+ * Colaborative Editing: Edit any page that others are editing at the same time and see their changes in real time.
103
+
104
+
105
+ == Installation
106
+
107
+ Include the gem in your Gemfile
108
+
109
+ gem 'mercury-rails'
110
+
111
+ Then just bundle install and you should be all set. Browse to any existing content page and prefix it's url with /edit,
112
+ so for instance, localhost:3000/edit/content/page to edit the content on /content/page.
113
+
114
+
115
+ == Usage
116
+
117
+ Mercury has an expectation that content regions will be on the page (not required, but probably useful). To define
118
+ content regions that Mercury will make editable you need to add a `mercury-region` class attribute to a div. Then
119
+ specify what region type by using the `data-type` attribute -- which can be *editable*, *markupable*, or *snippetable*.
120
+ Region types are outlined below.
121
+
122
+ <div class="mercury-region" data-type="editable">
123
+ default content
124
+ </div>
125
+
126
+
127
+ == Region Types
128
+
129
+ === Editable
130
+
131
+ Editable Regions are HTML markup, and use the HTML5 contentEditable feature. This is the core of what Mercury is about,
132
+ and provides the most flexibility and visual representation of what the content will look like when saved.
133
+
134
+ === Markupable
135
+
136
+ These regions are based on Markdown syntax (specifically the github flavored version), and isn't as full featured as the
137
+ editable region type -- primarily because markdown is meant to be simple, so to keep it such you can't do things like
138
+ set colors etc. This region type is super useful if you want to keep the markup clean and simple.
139
+
140
+ === Snippetable
141
+
142
+ Snippetable regions only allow snippets. There isn't any content editing in these regions, but snippets can sometimes
143
+ be the way to go with complex markup and functionality. Snippets are basically chunks of reusable markup, that can be
144
+ defined by a developer and placed into content regions later. More on this below.
145
+
146
+
147
+ == Snippets
148
+
149
+ Snippets are reusable and configurable chunks of markup. They can be defined by developers, and then placed anywhere in
150
+ content regions. When you drag a snippet into a region you'll be prompted to enter options, and after entering options
151
+ the snippet will be rendered into the page as a preview. Snippets can be dragged around (in snippetable regions) and
152
+ edited or removed.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,30 @@
1
+ /*!
2
+ * Mercury Editor is a Coffeescript and jQuery based WYSIWYG editor. Mercury Editor utilizes the HTML5 ContentEditable
3
+ * spec to allow editing sections of a given page (instead of using iframes) and provides an editing experience that's as
4
+ * realistic as possible. By not using iframes for editable regions it allows CSS to behave naturally.
5
+ *
6
+ * Mercury Editor was written for the future, and doesn't attempt to support legacy implementations of document editing.
7
+ *
8
+ * Currently supported browsers are
9
+ * - Firefox 4+
10
+ * - Chrome 10+
11
+ * - Safari 5+
12
+ *
13
+ * Copyright (c) 2011 Jeremy Jackson
14
+ *
15
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
16
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
17
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
18
+ * persons to whom the Software is furnished to do so, subject to the following conditions:
19
+ *
20
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
21
+ * Software.
22
+ *
23
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
24
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
25
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
26
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+ *
28
+ *= require_self
29
+ *= require mercury/mercury
30
+ */
@@ -0,0 +1,75 @@
1
+ class @Mercury.Dialog
2
+
3
+ constructor: (@url, @name, @options = {}) ->
4
+ @button = @options.for
5
+
6
+ @build()
7
+ @bindEvents()
8
+ @preload()
9
+
10
+
11
+ build: ->
12
+ @element = $('<div>', {class: "mercury-dialog mercury-#{@name}-dialog loading", style: 'display:none'})
13
+ @element.appendTo($(@options.appendTo).get(0) ? 'body')
14
+
15
+
16
+ bindEvents: ->
17
+ @element.mousedown (event) -> event.stopPropagation()
18
+
19
+
20
+ preload: ->
21
+ @load() if @options.preload
22
+
23
+
24
+ toggle: (element) ->
25
+ if @visible then @hide() else @show()
26
+
27
+
28
+ resize: ->
29
+ @show()
30
+
31
+
32
+ show: ->
33
+ Mercury.trigger('hide:dialogs', @)
34
+ @visible = true
35
+ if @loaded
36
+ @element.css({width: 'auto', height: 'auto'})
37
+ @position(@visible)
38
+ @appear()
39
+ else
40
+ @position()
41
+ @appear()
42
+
43
+
44
+ position: (keepVisible) ->
45
+
46
+
47
+ appear: ->
48
+ @element.css({display: 'block', opacity: 0})
49
+ @element.animate {opacity: .95}, 200, 'easeInOutSine', =>
50
+ @load(=> @resize()) unless @loaded
51
+
52
+
53
+ hide: ->
54
+ @element.hide()
55
+ @visible = false
56
+
57
+
58
+ load: (callback) ->
59
+ return unless @url
60
+ $.ajax @url, {
61
+ success: (data) =>
62
+ @loadContent(data)
63
+ Mercury.dialogHandlers[@name].call(@) if Mercury.dialogHandlers[@name]
64
+ callback() if callback
65
+ error: =>
66
+ @hide()
67
+ @button.removeClass('pressed') if @button
68
+ alert("Mercury was unable to load #{@url} for the #{@name} dialog.")
69
+ }
70
+
71
+
72
+ loadContent: (data) ->
73
+ @loaded = true
74
+ @element.removeClass('loading')
75
+ @element.html(data)
@@ -0,0 +1,6 @@
1
+ @Mercury.dialogHandlers.backcolor = ->
2
+ @element.find('.picker, .last-picked').click (event) =>
3
+ color = $(event.target).css('background-color')
4
+ @element.find('.last-picked').css({background: color})
5
+ @button.css({backgroundColor: color})
6
+ Mercury.trigger('action', {action: 'backcolor', value: color})
@@ -0,0 +1,6 @@
1
+ @Mercury.dialogHandlers.forecolor = ->
2
+ @element.find('.picker, .last-picked').click (event) =>
3
+ color = $(event.target).css('background-color')
4
+ @element.find('.last-picked').css({background: color})
5
+ @button.css({backgroundColor: color})
6
+ Mercury.trigger('action', {action: 'forecolor', value: color})
@@ -0,0 +1,4 @@
1
+ @Mercury.dialogHandlers.formatblock = ->
2
+ @element.find('[data-tag]').click (event) =>
3
+ tag = $(event.target).data('tag')
4
+ Mercury.trigger('action', {action: 'formatblock', value: tag})
@@ -0,0 +1,10 @@
1
+ @Mercury.dialogHandlers.objectspanel = ->
2
+ # make the filter work
3
+ @element.find('input.filter').keyup =>
4
+ value = @element.find('input.filter').val()
5
+ for snippet in @element.find('li[data-filter]')
6
+ if LiquidMetal.score($(snippet).data('filter'), value) == 0 then $(snippet).hide() else $(snippet).show()
7
+
8
+ # when an element is dragged, set it so we have a global object
9
+ @element.find('img[data-snippet]').bind 'dragstart', (event) ->
10
+ Mercury.snippet = $(@).data('snippet')
@@ -0,0 +1,4 @@
1
+ @Mercury.dialogHandlers.style = ->
2
+ @element.find('[data-class]').click (event) =>
3
+ className = $(event.target).attr('class')
4
+ Mercury.trigger('action', {action: 'style', value: className})
@@ -0,0 +1,30 @@
1
+ class @Mercury.HistoryBuffer
2
+
3
+ constructor: (@maxLength = 200) ->
4
+ @index = 0
5
+ @stack = []
6
+ @markerRegExp = /<em class="mercury-marker"><\/em>/g
7
+
8
+
9
+ push: (item) ->
10
+ if $.type(item) == 'string'
11
+ return if @stack[@index] && @stack[@index].replace(@markerRegExp, '') == item.replace(@markerRegExp, '')
12
+ else if $.type(item) == 'object' && item.html
13
+ return if @stack[@index] && @stack[@index].html == item.html
14
+
15
+ @stack = @stack[0...@index + 1]
16
+ @stack.push(item)
17
+ @stack.shift() if @stack.length > @maxLength
18
+ @index = @stack.length - 1
19
+
20
+
21
+ undo: ->
22
+ return null if @index < 1
23
+ @index -= 1
24
+ return @stack[@index]
25
+
26
+
27
+ redo: ->
28
+ return null if @index >= @stack.length - 1
29
+ @index += 1
30
+ return @stack[@index]
@@ -0,0 +1,293 @@
1
+ #
2
+ #= require jquery-1.6
3
+ #= require jquery-ui-1.8.13.custom.min
4
+ #= require jquery-ui-1.8.13.sortable.custom
5
+ #= require jquery.easing
6
+ #= require jquery.json2
7
+ #= require jquery.ujs
8
+ #= require jquery.serialize_object
9
+ #= require liquidmetal
10
+ #
11
+ #= require_self
12
+ #= require ./native_extensions
13
+ #= require ./page_editor
14
+ #= require ./history_buffer
15
+ #= require ./table_editor
16
+ #= require ./dialog
17
+ #= require ./palette
18
+ #= require ./select
19
+ #= require ./panel
20
+ #= require ./modal
21
+ #= require ./statusbar
22
+ #= require ./toolbar
23
+ #= require ./toolbar.button
24
+ #= require ./toolbar.button_group
25
+ #= require ./toolbar.expander
26
+ #= require ./tooltip
27
+ #= require ./snippet
28
+ #= require ./snippet_toolbar
29
+ #= require ./region
30
+ #= require ./uploader
31
+ #= require_tree ./regions
32
+ #= require_tree ./dialogs
33
+ #= require_tree ./modals
34
+ #
35
+ #= require showdown
36
+ #
37
+
38
+ @Mercury = {
39
+
40
+ version: 1.0
41
+
42
+
43
+ # No IE support yet because it doesn't follow the W3C standards for HTML5 contentEditable (aka designMode).
44
+ supported: document.getElementById && document.designMode && !$.browser.konqueror && !$.browser.msie
45
+
46
+
47
+ # Silent mode disables things like asking about unsaved changes before leaving the page.
48
+ silent: true
49
+
50
+
51
+ # Turning debug mode on will log events and other various things (using console.log if available).
52
+ debug: true
53
+
54
+
55
+ # Configuration
56
+ config: {
57
+
58
+ # Pasting (in Chrome/Safari)
59
+ #
60
+ # When copying content using webkit, it embeds all the user defined styles (from the css files) into the html style
61
+ # attributes directly. When pasting this content into HTML5 contentEditable elements it leaves these intact. This
62
+ # can be a desired feature, or an annoyance, so you can enable it or disable it here. Keep in mind this will only
63
+ # change the behavior in webkit, as gecko doesn't do this.
64
+ #
65
+ cleanStylesOnPaste: true
66
+
67
+
68
+ # Image Uploading (in supported regions)
69
+ #
70
+ # If you drag images (while pressing shift) from your desktop into regions that support it, it will be uploaded to
71
+ # the server and inserted into the region. This configuration allows you to specify if you want to disable/enable
72
+ # this feature, the accepted mime-types, file size restrictions, and other things related to uploading.
73
+ #
74
+ uploading:
75
+ enabled: true
76
+ allowedMimeTypes: ['image/jpeg', 'image/gif', 'image/png']
77
+ maxFileSize: 1235242880 # bytes (5 Mb by default)
78
+ inputName: 'image[image]'
79
+ url: '/images'
80
+
81
+
82
+ # Toolbars
83
+ #
84
+ # This is where you can customize the toolbars by adding or removing buttons, or changing them and their behaviors.
85
+ # Any top level object put here will create a new toolbar. Buttons are simply nested inside the toolbars, along
86
+ # with button groups.
87
+ #
88
+ # Buttons can be grouped. A button group is simply a way to wrap buttons for styling, and can also handle enabling
89
+ # or disabling all the buttons within it by using a context. The table button group is a good example of this.
90
+ #
91
+ # The primary toolbar is always visible, but any other toolbar should have a name based on what type of region it's
92
+ # for. The toolbar will be enabled/disabled base on what region currently has focus. Some toolbars are custom (the
93
+ # snippetable toolbar for instance), and to denote that use _custom: true. You can then build the toolbar yourself
94
+ # with it's own behavior.
95
+ #
96
+ # It's important to note that each of the button names (keys), in each toolbar object must be unique, regardless of
97
+ # if it's in a button group, or nested, etc. This is because styling is applied to them by name.
98
+ #
99
+ # Button format: [label, description, {type: action, type: action, etc}] The available button types are:
100
+ #
101
+ # toggle: toggles on or off when clicked, otherwise behaves like a button
102
+ # modal: opens a modal window, expects the action to be one of:
103
+ # a string url
104
+ # a function that returns a string url
105
+ # panel: opens a panel dialog, expects the action to be one of:
106
+ # a string url
107
+ # a function that returns a string url
108
+ # palette: opens a palette window, expects the action to be one of:
109
+ # a string url
110
+ # a function that returns a string url
111
+ # select: opens a pulldown style window, expects the action to be one of:
112
+ # a string url
113
+ # a function that returns a string url
114
+ # context: calls a callback function, expects the action to be:
115
+ # a function that returns a boolean to highlight the button
116
+ # note: if a function isn't provided, the key will be passed to the contextHandler, in which case a
117
+ # default context will be used (for more info read the Contexts section below)
118
+ # mode: toggle a given mode in the editor, expects the action to be:
119
+ # a string, denoting the name of the mode
120
+ # note: it's assumed that when a specific mode is turned on, all other modes will be turned off, which
121
+ # happens automatically, thus putting the editor into a specific "state"
122
+ # regions: allows buttons to be enabled/disabled based on what region type has focus, expects the action to be:
123
+ # an array of region types (eg. ['editable', 'markupable']
124
+ # preload: allows some dialog views to be loaded whtn the button is created instead of on first open, expects:
125
+ # a boolean
126
+ # note: only used for panels, selects, and palettes
127
+ #
128
+ # Separators are any "button" that's not an array, and are expected to be a string. You can use two different
129
+ # separator styles: line ('-'), and spacer (' ').
130
+ #
131
+ toolbars:
132
+ primary:
133
+ save: ['Save', 'Save this page']
134
+ preview: ['Preview', 'Preview this page', {toggle: true, mode: true}]
135
+ sep1: ' '
136
+ undoredo:
137
+ undo: ['Undo', 'Undo your last action']
138
+ redo: ['Redo', 'Redo your last action']
139
+ sep: ' '
140
+ insertlink: ['Link', 'Insert Link', {modal: '/mercury/modals/link', regions: ['editable', 'markupable']}]
141
+ insertmedia: ['Media', 'Insert Media (images and videos)', {modal: '/mercury/modals/media', regions: ['editable', 'markupable']}]
142
+ inserttable: ['Table', 'Insert Table', {modal: '/mercury/modals/table', regions: ['editable', 'markupable']}]
143
+ insertcharacter: ['Character', 'Special Characters', {modal: '/mercury/modals/character', regions: ['editable', 'markupable']}]
144
+ objectspanel: ['Snippet', 'Snippet Panel', {panel: '/mercury/panels/snippets'}]
145
+ sep2: ' '
146
+ historypanel: ['History', 'Page Version History', {panel: '/mercury/panels/history'}]
147
+ sep3: ' '
148
+ notespanel: ['Notes', 'Page Notes', {panel: '/mercury/panels/notes'}]
149
+
150
+ editable:
151
+ _regions: ['editable', 'markupable']
152
+ predefined:
153
+ style: ['Style', null, {select: '/mercury/selects/style', preload: true}]
154
+ sep1: ' '
155
+ formatblock: ['Block Format', null, {select: '/mercury/selects/formatblock', preload: true}]
156
+ sep2: '-'
157
+ colors:
158
+ _regions: ['editable']
159
+ backcolor: ['Background Color', null, {palette: '/mercury/palettes/backcolor', context: true, preload: true}]
160
+ sep1: ' '
161
+ forecolor: ['Text Color', null, {palette: '/mercury/palettes/forecolor', context: true, preload: true}]
162
+ sep2: '-'
163
+ decoration:
164
+ bold: ['Bold', null, {context: true}]
165
+ italic: ['Italicize', null, {context: true}]
166
+ overline: ['Overline', null, {context: true, regions: ['editable']}]
167
+ strikethrough: ['Strikethrough', null, {context: true, regions: ['editable']}]
168
+ underline: ['Underline', null, {context: true, regions: ['editable']}]
169
+ sep: '-'
170
+ script:
171
+ subscript: ['Subscript', null, {context: true}]
172
+ superscript: ['Superscript', null, {context: true}]
173
+ sep: '-'
174
+ justify:
175
+ _regions: ['editable']
176
+ justifyleft: ['Align Left', null, {context: true}]
177
+ justifycenter: ['Center', null, {context: true}]
178
+ justifyright: ['Align Right', null, {context: true}]
179
+ justifyfull: ['Justify Full', null, {context: true}]
180
+ sep: '-'
181
+ list:
182
+ insertunorderedlist: ['Unordered List', null, {context: true}]
183
+ insertorderedlist: ['Numbered List', null, {context: true}]
184
+ sep: '-'
185
+ indent:
186
+ outdent: ['Decrease Indentation', null]
187
+ indent: ['Increase Indentation', null]
188
+ sep: '-'
189
+ table:
190
+ _context: true
191
+ _regions: ['editable']
192
+ insertrowbefore: ['Insert Table Row', 'Insert a table row before the cursor']
193
+ insertrowafter: ['Insert Table Row', 'Insert a table row after the cursor']
194
+ deleterow: ['Delete Table Row', 'Delete this table row']
195
+ insertcolumnbefore: ['Insert Table Column', 'Insert a table column before the cursor']
196
+ insertcolumnafter: ['Insert Table Column', 'Insert a table column after the cursor']
197
+ deletecolumn: ['Delete Table Column', 'Delete this table column']
198
+ sep1: ' '
199
+ increasecolspan: ['Increase Cell Columns', 'Increase the cells colspan']
200
+ decreasecolspan: ['Decrease Cell Columns', 'Decrease the cells colspan and add a new cell']
201
+ increaserowspan: ['Increase Cell Rows', 'Increase the cells rowspan']
202
+ decreaserowspan: ['Decrease Cell Rows', 'Decrease the cells rowspan and add a new cell']
203
+ sep2: '-'
204
+ rules:
205
+ horizontalrule: ['Horizontal Rule', 'Insert a horizontal rule']
206
+ sep1: '-'
207
+ formatting:
208
+ _regions: ['editable']
209
+ removeformatting: ['Remove Formatting', 'Remove formatting for the selection']
210
+ sep2: ' '
211
+ editors:
212
+ _regions: ['editable']
213
+ htmleditor: ['Edit HTML', 'Edit the HTML content'] # example behavior below
214
+
215
+ snippetable:
216
+ _custom: true
217
+ actions:
218
+ editsnippet: ['Edit Snippet Settings', null]
219
+ sep1: ' '
220
+ removesnippet: ['Remove Snippet', null]
221
+
222
+
223
+ # Behaviors
224
+ #
225
+ # Behaviors are used to change the default behaviors of a given region type when a given button is clicked. For
226
+ # example, you may prefer to add HR tags using an HR wrapped within a div with a classname (for styling). You can
227
+ # add your own complex behaviors here.
228
+ #
229
+ # You can see how the behavior matches up directly with the button name. It's also important to note that the
230
+ # callback functions are executed within the scope of the given region, so you have access to all it's methods.
231
+ # todo: figure out how this impacts different regions.. should they go away, or should they get moved into region types?
232
+ behaviors:
233
+ horizontalrule: (selection) -> selection.replace('<hr/>')
234
+
235
+ htmleditor: ->
236
+ Mercury.modal '/mercury/modals/htmleditor', {
237
+ title: 'HTML Editor',
238
+ fullHeight: true,
239
+ handler: 'htmleditor'
240
+ }
241
+
242
+
243
+ # Contexts
244
+ #
245
+ # Contexts are used callback functions used for highlighting and disabling/enabling buttons and buttongroups. When
246
+ # the cursor enters an element within an html region for instance we want to disable or highlight buttons based on
247
+ # the properties of the given node. You can see some examples of contexts in:
248
+ #
249
+ # Mercury.Toolbar.Button.contexts
250
+ # and
251
+ # Mercury.Toolbar.ButtonGroup.contexts
252
+ #
253
+
254
+
255
+ # Styles
256
+ #
257
+ # Mercury tries to stay as much out of your code as possible, but because regions appear within your document we
258
+ # need to include a few styles to indicate regions, as well as the different states of them (eg. focused). These
259
+ # styles are injected into your document, and as simple as they might be, you may want to change them. You can do
260
+ # so here.
261
+ #
262
+ injectedStyles: '''
263
+ .mercury-region, .mercury-textarea { min-height: 10px; outline: 1px dotted #09F }
264
+ .mercury-textarea { box-sizing: border-box; -moz-box-sizing: border-box; resize: vertical; }
265
+ .mercury-region:focus, .mercury-region.focus, .mercury-textarea.focus { outline: none; -webkit-box-shadow: 0 0 10px #09F, 0 0 1px #045; box-shadow: 0 0 10px #09F, 0 0 1px #045 }
266
+ .mercury-region:after { content: '\00a0'; display: block; visibility: hidden; clear: both; height: 0; overflow: hidden; }
267
+ .mercury-region table, .mercury-region td { border: 1px dotted red; }
268
+ '''
269
+ }
270
+
271
+
272
+ # Custom event and logging methods
273
+ bind: (eventName, callback) ->
274
+ $(document).bind("mercury:#{eventName}", callback)
275
+
276
+
277
+ trigger: (eventName, options) ->
278
+ Mercury.log(eventName, options)
279
+ $(document).trigger("mercury:#{eventName}", options)
280
+
281
+
282
+ log: ->
283
+ if Mercury.debug && console
284
+ return if arguments[0] == 'hide:toolbar'
285
+ try console.debug(arguments) catch e
286
+
287
+
288
+ # Mercury object namespaces
289
+ Regions: {}
290
+ modalHandlers: {}
291
+ dialogHandlers: {}
292
+
293
+ }